﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;

namespace Radiation___IM
{
    public class MessageExecution
    {
        public static void Execute(MessageParser parser, Client client)
        {
            if (parser.Message.Length > 0)
            {
                if (parser.Message.StartsWith("/"))
                {
                    string command = parser.Message.Substring(1);
                    CommandExecution(command, client, (string)parser.Parameters["channel"]);
                }
                else
                {
                    if ((string)parser.Parameters["channel"] != null && 
                        ChannelManager.Instance[(string)parser.Parameters["channel"]] != null)
                    {
                        ChannelManager.Instance[(string)parser.Parameters["channel"]]
                            .dispatchMessage(parser.Message, client);
                    }
                    else
                        sendData(client, "Invalid channel");
                }                                       
            }
            // else nothing to do
        }

        public static void sendData(Client client, string message)
        {
            byte[] buffer = UnicodeEncoding.Unicode.GetBytes(client.AESProvider.Encrypt("[channel=default;user=system;a=0]" + message));
            client.Handler.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(dataSent), client);
        }

        public static void sendDataMultiple(Client client, string[] message)
        {
            for (int i = 0; i < message.Length; i++)
            {
                byte[] buffer = UnicodeEncoding.Unicode.GetBytes(client.AESProvider.Encrypt("[channel=default;user=system;a=0]" + message[i]));
                client.Handler.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(dataSent), client);
                Thread.Sleep(20);
            }
        }

        public static void sendDataAPI(Client client, string message, string command)
        {
            byte[] buffer = UnicodeEncoding.Unicode.GetBytes(client.AESProvider.Encrypt("[channel=default;user=system;a=1;ap=" + command + "]" + message));
            client.Handler.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(dataSent), client);
        }

        public static void sendData(Client client, string message, string channel, string user)
        {
            byte[] buffer = UnicodeEncoding.Unicode.GetBytes(client.AESProvider.Encrypt("[channel=" + channel + ";user=" + user + ";a=0]" + message));
            client.Handler.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(dataSent), client);
        }

        public static void sendDataSystem(Client client, string message, string channel)
        {
            byte[] buffer = UnicodeEncoding.Unicode.GetBytes(client.AESProvider.Encrypt("[channel=" + channel + ";user=system;a=0]" + message));
            client.Handler.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(dataSent), client);
        }

        public static void dataSent(IAsyncResult result)
        {
            ((Client)result.AsyncState).Handler.EndSend(result);
        }

        private static void CommandExecution(string command, Client client, string channel)
        {
            string[] command_parts = command.Split(new char[] {' '});

            if (command_parts.Length > 0 && command_parts[0].Length > 0)
            {
                if (command_parts[0] == "api")
                {
                    //ApiExec(command_parts, client); 
                    if (CommandManager.Instance.ExecuteAPICommand(command_parts, client) == rvalue.COMMAND_NOT_FOUND)
                        sendDataAPI(client, "Invalid API command", command_parts[1]);
                }
                else
                {
                    if (CommandManager.Instance.ExecuteCommand(command_parts, client, channel) == rvalue.COMMAND_NOT_FOUND)
                        sendData(client, "Command not recognized");
                }
            }
        }

        public static void NoticeChannels(Client client, string message)
        {
            foreach (Channel chan in client.Channels.Values)
            {
                chan.dispatchMessageSystem(message, client);
            }
        }

        public static void NoticeChannelsAPI(Client client, string message, string command)
        {
            foreach (Channel chan in client.Channels.Values)
            {
                chan.dispatchMessageAPI(chan.Name+";"+message, command);
            }
        }

        /*private static void ApiExec(string[] commands, Client client)
        {
            if (commands.Length > 1)
            {
                switch (commands[1])
                {
                    /*case "user.nickname":
                        sendDataAPI(client, client.Nickname, commands[1]);
                        break;
                    case "channels.list":
                        StringBuilder channels = new StringBuilder();

                        foreach (Channel chan in ChannelManager.Instance.Channels.Values)
                            channels.Append(chan.Name + ",");

                        sendDataAPI(client, channels.ToString().Substring(0, channels.ToString().Length - 1), commands[1]);
                        break;
                    case Radiation.Common.Communication.APIMethods.GET_CHANNEL_USERS:
                        if (commands.Length >= 3 &&
                            commands[2].Length > 2)
                        {
                            StringBuilder users = new StringBuilder();
                            if (ChannelManager.Instance[commands[2]] != null)
                            {
                                foreach (Client username in ChannelManager.Instance[commands[2]].Users)
                                    if (!username.Invisible)
                                        users.Append(username.Nickname+";");
                                sendDataAPI(client, commands[2]+";"+users.ToString().Substring(0, users.ToString().Length - 1), commands[1]);
                            }
                            else
                                sendDataAPI(client, commands[2] + ";", commands[1]);
                        }
                        break;
                    case "channels.join_or_create":
                        if (commands.Length >= 3 &&
                            commands[2].Length > 2)
                        {
                            if (ChannelManager.Instance[commands[2]] == null)
                            {
                                ChannelManager.Instance.add(commands[2]);
                                ChannelManager.Instance[commands[2]].registerClient(client, true);
                                ChannelManager.Instance[commands[2]].dispatchMessageSystem(client.Nickname + " has created this channel");
                                ChannelManager.Instance[commands[2]].sendMotd(client);
                            }
                            else
                                ChannelManager.Instance[commands[2]].registerClient(client);
                        }
                        break;
                    case Radiation.Common.Communication.APIMethods.LOGIN:
                        if (commands.Length >= 4 &&
                            commands[2].Length > 1 &&
                            commands[3].Length > 1)
                        {
                            // Continue
                            if (Users.UserManager.Instance[commands[2]] != null)
                            {
                                if (Users.UserManager.Instance[commands[2]].Password == commands[3])
                                {
                                    sendDataAPI(client, Radiation.Common.Communication.Constants.LOGIN_SUCESS, Radiation.Common.Communication.APIMethods.LOGIN);
                                    Thread.Sleep(200);
                                    Commands.Nick.changeNick(commands[2], client);
                                }
                                else
                                    sendDataAPI(client, Radiation.Common.Communication.Constants.LOGIN_BAD_PASSWORD, Radiation.Common.Communication.APIMethods.LOGIN);
                            }
                            else
                                sendDataAPI(client, Radiation.Common.Communication.Constants.LOGIN_BAD_NICKNAME, Radiation.Common.Communication.APIMethods.LOGIN);
                        }
                        else
                            sendDataAPI(client, Radiation.Common.Communication.Constants.LOGIN_ERROR, Radiation.Common.Communication.APIMethods.LOGIN);
                        break;
                    case Radiation.Common.Communication.APIMethods.CLIENT_SET_INVISIBLE:
                        if (!client.Invisible)
                            Commands.Invisible.switchInvisibility(client);
                        break;
                    case Radiation.Common.Communication.APIMethods.CLIENT_SET_VISIBLE:
                        if (client.Invisible)
                            Commands.Invisible.switchInvisibility(client);
                        break;
                    case Radiation.Common.Communication.APIMethods.ADD_FRIEND:
                        if (Users.UserManager.Instance[client.Nickname] != null &&
                            commands.Length > 2 &&
                            commands[2].Length > 1) // if user is logged in and input valid
                        {
                            if (Users.UserManager.Instance[commands[2]] != null)
                            {
                                if (Users.UserManager.Instance[client.Nickname].Friends.Contains(commands[2]))
                                {
                                    sendDataAPI(client,
                                         Radiation.Common.Communication.Constants.ADDFRIEND_ALREADY_ADDED + ";",
                                         commands[1]);
                                }
                                else
                                {
                                    // Everything's fine
                                    Users.UserManager.Instance[client.Nickname].Friends.Add(commands[2]);
                                    sendDataAPI(client,
                                        Radiation.Common.Communication.Constants.ADDFRIEND_SUCCESS + ";" + commands[2],
                                        commands[1]);
                                    sendDataAPI(client,
                                         commands[2],
                                         Radiation.Common.Communication.APIMethods.CLIENT_ADD_FRIEND);
                                    Data.DatabaseWriter.Instance.Queue(Users.UserManager.Instance[client.Nickname].getFile());
                                }
                            }
                            else
                            {
                                // the user does not exists
                                sendDataAPI(client,
                                    Radiation.Common.Communication.Constants.ADDFRIEND_ACCOUNT_NOT_FOUND + ";",
                                    commands[1]);
                            }
                        }
                        else
                            sendDataAPI(client,
                                Radiation.Common.Communication.Constants.ADDFRIEND_ERROR + ";",
                                commands[1]);

                        break;
                    case Radiation.Common.Communication.APIMethods.REMOVE_FRIEND:
                        {
                            if (Users.UserManager.Instance[client.Nickname] != null &&
                                commands.Length > 2 &&
                                commands[2].Length > 1) // if user is logged in and input valid
                            {
                                if (Users.UserManager.Instance[client.Nickname].Friends.Contains(commands[2]))
                                {
                                    Users.UserManager.Instance[client.Nickname].Friends.Remove(commands[2]);
                                    sendDataAPI(client,
                                        Radiation.Common.Communication.Constants.REMOVEFRIEND_SUCCESS,
                                        commands[1]);
                                    sendDataAPI(client,
                                        commands[2],
                                        Radiation.Common.Communication.APIMethods.CLIENT_REMOVE_FRIEND);
                                    Data.DatabaseWriter.Instance.Queue(Users.UserManager.Instance[client.Nickname].getFile());
                                }
                                else
                                    sendDataAPI(client,
                                        Radiation.Common.Communication.Constants.REMOVEFRIEND_NOT_EXISTS,
                                        commands[1]);
                            }
                            else
                                sendDataAPI(client,
                                    Radiation.Common.Communication.Constants.REMOVEFRIEND_NOT_LOGGED_IN,
                                    commands[1]);
                        }
                        break;
                    case Radiation.Common.Communication.APIMethods.CREATE_ACCOUNT:
                        {
                            if (commands.Length > 3 &&
                                commands[2].Length > 1 &&
                                commands[3].Length > 0)
                            {
                                if (Users.UserManager.Instance[commands[2]] == null)
                                {
                                    Users.User user = new Users.User();
                                    user.Nickname = commands[2];
                                    user.Password = commands[1];
                                    Users.UserManager.Instance.addUser(user);

                                    sendDataAPI(client,
                                        Radiation.Common.Communication.Constants.ACCOUNT_CREATION_SUCESS,
                                        commands[1]);
                                }
                                else
                                    sendDataAPI(client,
                                        Radiation.Common.Communication.Constants.ACCOUNT_CREATION_ALREADY_EXISTS,
                                        commands[1]);
                            }
                            else
                                sendDataAPI(client,
                                    Radiation.Common.Communication.Constants.ACCOUNT_CREATION_ERROR,
                                    commands[1]);

                        }
                        break;
                    default:
                        sendDataAPI(client, "Invalid API command", commands[1]);
                        break;
                }
            }
            else
                sendDataAPI(client, "Invalid API command", commands[1]);
        }*/
    }
}
